﻿using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using YouWei.Infrastructure.Entity;
using YouWei.Infrastructure.Enums;
using YouWei.Infrastructure.Service;
using YouWei.Utility;

namespace WxCollect
{
    public partial class Form1 : Form
    {
        static ReaderWriterLockSlim LogWriteLock = new ReaderWriterLockSlim();
        GcGroupService groupService = new GcGroupService();
        GcGroupUserService groupUserService = new GcGroupUserService();
        GcMsgContentAudioService audioService = new GcMsgContentAudioService();
        GcMsgContentImageService imageService = new GcMsgContentImageService();
        GcMsgContentTextService textService = new GcMsgContentTextService();
        GcMsgContentLinkService linkService = new GcMsgContentLinkService();
        GcMsgContentVideoService videoService = new GcMsgContentVideoService();
        GcChatMessageService msgService = new GcChatMessageService();
        JobRecordService jobService = new JobRecordService();
        GcMsgContenCardService cardService = new GcMsgContenCardService();
        GcMsgContentAlbumService albumService = new GcMsgContentAlbumService();
        GcMsgContentFileService fileService = new GcMsgContentFileService();

        /// <summary>
        /// 登陆账号
        /// </summary>
        private string UserName {
            get {
                return SiteUtility.GetAppSettings("UserName");
            }
        }

        /// <summary>
        /// 登陆密码
        /// </summary>
        private string UserPwd
        {
            get
            {
                return SiteUtility.GetAppSettings("UserPwd");
            }
        }

        //cookie缓存
        protected CookieContainer ck = new CookieContainer();

        public Form1()
        {
            InitializeComponent();
            webBrowser1.ScriptErrorsSuppressed = true;
            timer1.Start();
        }

        private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
        {
            ((WebBrowser)sender).Document.Window.Error += new HtmlElementErrorEventHandler(Window_Error);
            GetCookies(webBrowser1.Url.ToString());
            Login();
            PostData();
            Thread thread = new Thread(ErrorCollect);
            thread.Start();  // 只要使用Start方法，线程才会运行  
           
        }

        /// <summary>
        /// 获取地址
        /// </summary>
        /// <param name="url"></param>
        private void GetCookies(string url)
        {
            ck = new CookieContainer();
            string cookie = CookieReader.GetCookie(url);
            if (!string.IsNullOrEmpty(cookie))
            {
                string[] strs = cookie.Split(new char[] { ';' });
                foreach (var item in strs)
                {
                    string[] strs1 = item.Split(new char[] { '=' });
                    var cke = new Cookie(strs1[0].Trim(), strs1[1].Trim().Split(',')[0])
                    {
                        Domain = webBrowser1.Document.Url.Host,
                        Expired = false,
                        Expires = DateTime.Now.AddDays(1),
                        HttpOnly = true
                    };
                    ck.Add(cke);
                }
            }
        }

        /// <summary>
        /// 请求
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void PostData()
        {
            if (ck!=null)
            {
                var rts = RequestHelper.GetHtml("https://wp-api.wxb.com/chat/listMember?wxid=wxid_ecgmb3z00be722&member_type=2", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36", ck);
                GroupResult list = JsonConvert.DeserializeObject<GroupResult>(rts);
                foreach (var item in list.data)
                {
                    string mId = "";
                    string mIndex = "";
                    int groupId = AddGroup(item);
                    List<GcGroupUser> userList = groupUserService.GetListByGroupId(groupId);
                    GetUserChatList(item.wxid, groupId,out mId,out mIndex, userList);
                    if (!string.IsNullOrWhiteSpace(mId)&&!string.IsNullOrWhiteSpace(mIndex))
                    {
                        Thread.Sleep(500);
                        userList = groupUserService.GetListByGroupId(groupId);
                        GetUserChatListUp(item.wxid, groupId, mId, mIndex, userList,false);
                    }
                }
            }
            else
            {

            }

        }

        /// <summary>
        /// 添加群
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        private int AddGroup(GroupInfo item)
        {
            int groupId = 0;
            GcGroup info = groupService.GetInfoByWxId(item.wxid);
            if (info == null)
            {
                info = new GcGroup
                {
                    avatar = item.avatar,
                    wxid = item.wxid,
                    CreatedTime = DateTime.Now,
                    member_count = item.member_count,
                    nickname = item.nickname,
                    owner_wxid = item.owner_wxid
                };
                object obj = groupService.Insert(info);
                if (obj != null)
                {
                    groupId = EConvert.ToInt(obj);
                }
            }
            else {
                bool isUpdate = false;
                if (info.avatar!= item.avatar)
                {
                    isUpdate = true;
                    info.avatar = item.avatar;
                }
                if (info.member_count != item.member_count)
                {
                    isUpdate = true;
                    info.member_count = item.member_count;
                }
                if (info.nickname != item.nickname)
                {
                    isUpdate = true;
                    info.nickname = item.nickname;
                }
                if (info.owner_wxid != item.owner_wxid)
                {
                    isUpdate = true;
                    info.owner_wxid = item.owner_wxid;
                }
                if (isUpdate)
                {
                    info.UpdatedTime = DateTime.Now;
                    groupService.Update(info);
                }
                groupId =  info.GroupID;
            }
            return groupId;
        }

        /// <summary>
        /// 获取最新聊天信息
        /// </summary>
        /// <param name="wxid"></param>
        /// <param name="groupId"></param>
        /// <param name="id"></param>
        /// <param name="index"></param>
        /// <param name="userList"></param>
        private void GetUserChatList(string wxid,int groupId,out string id,out string index, List<GcGroupUser> userList)
        {
            id = "";
            index = "";
            var rts = RequestHelper.GetHtml(string.Format("https://wp-api.wxb.com/chat/history?wxid=wxid_ecgmb3z00be722&wxid2={0}&session_type=2&history_type=latest&msg_type=0",wxid), "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36", ck);
            ChatResult list = JsonConvert.DeserializeObject<ChatResult>(jsonString(rts));
            AddJobRecord(groupId, new ReqMessagePage { MsgId = "latest", MsgIndex = "", WxId = wxid });
            List<GcChatMessage> msgList = null;
            int i = 0;
            Dictionary<string, string> dic = new Dictionary<string, string>();
            foreach (var item in list.data)
            {
                if (i==0)
                {
                    id = item._id;
                    index = item._index;
                    msgList = msgService.GetTop10LatestInfoBySendTime(groupId);
                }
                i++;
                //如果库中没有用户则添加
                if (!userList.Where(m=>m.wxid==item.from_wxid).Any()&& !dic.ContainsKey(item.from_wxid))
                {
                    dic.Add(item.from_wxid, item.from_wxid);
                    AddUser(item, groupId);
                }
                //添加消息
                if (!msgList.Where(m=>m.client_msgid==item.message_id).Any())
                {
                    int msgId = AddMessage(item, groupId);
                    AddContent(item, msgId);
                }
                

            }
            jobService.UpdateLastDataRecordTime(groupId, (int)JobEnum.WxMsgCollect, i);

        }

        private void AddContent(ChatInfo item,int msgId)
        {
            switch (item.msg_type)
            {
                case 1:
                case 100:
                    AddText(item.content.text, msgId);
                    break;
                case 2:
                    AddImage(item.content.url, msgId);
                    break;
                case 3:
                    AddLink(item.content, msgId);
                    break;
                case 4:
                    AddAudio(item.content.url, msgId);
                    break;
                case 5:
                    AddVideo(item.content.url, msgId);
                    break;
                case 6:
                    AddFile(item.content, msgId);
                    break;
                case 7:
                    AddCard(item.content, msgId);
                    break;
                case 8:
                    AddAlbum(item.content, msgId);
                    break;
                case 9:
                    AddImage(item.content.url, msgId);
                    break;
            }
        }

        /// <summary>
        /// 向上分页取数据
        /// </summary>
        /// <param name="wxid"></param>
        /// <param name="groupId"></param>
        /// <param name="id"></param>
        /// <param name="index"></param>
        /// <param name="userList"></param>
        private void GetUserChatListUp(string wxid, int groupId, string id, string index, List<GcGroupUser> userList,bool isJobRecord)
        {
            var rts = RequestHelper.GetHtml(string.Format("https://wp-api.wxb.com/chat/history?wxid=wxid_ecgmb3z00be722&wxid2={0}&session_type=2&direction=1&anchor_id={1}&anchor_index={2}&msg_type=0", wxid, id, index), "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36", ck);
            ChatResult list = JsonConvert.DeserializeObject<ChatResult>(jsonString(rts));
            AddJobRecord(groupId, new ReqMessagePage { MsgId = id, MsgIndex = index, WxId=wxid });
            List<GcChatMessage> msgList = null;
            Dictionary<string, string> dic = new Dictionary<string, string>();
            string cId = "";
            string cIndex = "";
            int i = 0;
            foreach (var item in list.data)
            {
                if (i == 0)
                {
                    cId = item._id;
                    cIndex = item._index;
                    DateTime cTime = ConvertIntDateTime(long.Parse(item.client_time));
                    msgList = msgService.GetTop10LatestInfoBySendTime(cTime, groupId);
                }

                //如果库中没有用户则添加
                if (!userList.Where(m => m.wxid == item.from_wxid).Any() && !dic.ContainsKey(item.from_wxid))
                {
                    dic.Add(item.from_wxid, item.from_wxid);
                    AddUser(item, groupId);
                }
                //添加消息
                if (!msgList.Where(m => m.client_msgid == item.message_id).Any())
                {
                    i++;
                    int msgId = AddMessage(item, groupId);
                    AddContent(item, msgId);
                }
                

            }
            jobService.UpdateLastDataRecordTime(groupId, (int)JobEnum.WxMsgCollect, i);
            if (i==10||isJobRecord)
            {
                Thread.Sleep(500);
                userList = groupUserService.GetListByGroupId(groupId);
                GetUserChatListUp(wxid, groupId, cId, cIndex, userList,false);
            }

        }

        private void test()
        {
            var rts = RequestHelper.GetHtml("https://wp-api.wxb.com/chat/history?wxid=wxid_ecgmb3z00be722&wxid2=19353478417@chatroom&session_type=2&direction=1&anchor_id=bc1JOW4B-bU6oGqFTKID&anchor_index=wp_chat-20191105&msg_type=0", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36", ck);
            ChatResult list = JsonConvert.DeserializeObject<ChatResult>(jsonString(rts));
            foreach (var item in list.data)
            {
               
                //添加消息
                if (item.msg_type==6)
                {

                    AddContent(item, 39217);
                }


            }
            
        }

        /// <summary>
        /// 添加用户
        /// </summary>
        /// <param name="item"></param>
        /// <param name="groupId"></param>
        private void AddUser(ChatInfo item,int groupId)
        {
            GcGroupUser userObj = new GcGroupUser
                {
                    GroupID = groupId,
                    IsDeleted = 0,
                    avatar = item.from_user.avatar,
                    CreatedTime = DateTime.Now,
                    nickname = item.from_user.nickname,
                    remark = item.from_user.remark,
                    wxid = item.from_wxid.Replace(" ",""),
                    wx_alias = item.from_user.wx_alias
                };
                groupUserService.Insert(userObj);
        }

        private int AddMessage(ChatInfo item, int groupId)
        {
            DateTime cTime = ConvertIntDateTime(long.Parse(item.client_time));
            List<GcChatMessage> list = msgService.GetTop10LatestInfoBySendTime(cTime, groupId);
            GcChatMessage msgObj = new GcChatMessage
            {
                client_time = cTime,
                CreatedTime = DateTime.Now,
                from_wxid = item.from_user.wxid,
                GroupID = groupId,
                msg_type = item.msg_type,
                to_wxid = item.to_wxid,
                client_msgid = item.message_id
            };
            object obj = msgService.Insert(msgObj);
            if (obj != null)
            {
                return EConvert.ToInt(obj);
            }
            return 0;
        }

        private int AddAudio(string content,int messageId)
        {
            GcMsgContentAudio info = new GcMsgContentAudio
            {
                MessageID = messageId,
                url = content
            };
            object obj = audioService.Insert(info);
            if (obj != null)
            {
               return EConvert.ToInt(obj);
            }
            return 0;
        }

        private int AddImage(string content, int messageId)
        {
            GcMsgContentImage info = new GcMsgContentImage
            {
                MessageID = messageId,
                url = content
            };
            object obj = imageService.Insert(info);
            if (obj != null)
            {
                return EConvert.ToInt(obj);
            }
            return 0;
        }

        private int AddLink(Content content, int messageId)
        {
            GcMsgContentLink info = new GcMsgContentLink
            {
                MessageID = messageId,
                url = content.url,
                cover = content.cover,
                desc = content.desc,
                raw_msg = content.raw_msg,
                title = content.title
            };
            object obj = linkService.Insert(info);
            if (obj != null)
            {
                return EConvert.ToInt(obj);
            }
            return 0;
        }

        private int AddText(string content, int messageId)
        {
            GcMsgContentText info = new GcMsgContentText
            {
                MessageID = messageId,
                Text = content
            };
            object obj = textService.Insert(info);
            if (obj != null)
            {
                return EConvert.ToInt(obj);
            }
            return 0;
        }

        private int AddVideo(string content, int messageId)
        {
            GcMsgContentVideo info = new GcMsgContentVideo
            {
                MessageID = messageId,
                url = content
            };
            object obj = videoService.Insert(info);
            if (obj != null)
            {
                return EConvert.ToInt(obj);
            }
            return 0;
        }

        private int AddAlbum(Content content, int messageId)
        {
            GcMsgContentAlbum info = new GcMsgContentAlbum
            {
                MessageID = messageId,
                appid = content.appid,
                cover = content.cover,
                name = content.name,
                raw_msg = content.raw_msg,
                title = content.title,
                weapp_iconurl = content.weapp_iconurl
            };
            object obj = albumService.Insert(info);
            if (obj != null)
            {
                return EConvert.ToInt(obj);
            }
            return 0;
        }

        private int AddFile(Content content, int messageId)
        {
            GcMsgContentFile info = new GcMsgContentFile
            {
                MessageID = messageId,
                raw_msg = content.raw_msg,
                title = content.title,
                desc = content.desc,
                ext = content.ext,
                url = content.url
            };
            object obj = fileService.Insert(info);
            if (obj != null)
            {
                return EConvert.ToInt(obj);
            }
            return 0;
        }

        private int AddCard(Content content, int messageId)
        {
            GcMsgContenCard info = new GcMsgContenCard
            {
                MessageID = messageId,
                avatar = content.user_info.avatar,
                type = content.type,
                nickname = content.user_info.nickname,
                wxid = content.user_info.wxid
            };
            object obj = cardService.Insert(info);
            if (obj != null)
            {
                return EConvert.ToInt(obj);
            }
            return 0;
        }

        private void Login()
        {
            CookieCollection outCookies = null;
            string postData = string.Format("email={0}&from=http://wp.wxb.com&password={1}&remember=no&captcha=", UserName, UserPwd);
            ApiResult rt = RequestHelper.PostHtml("https://account.wxb.com/index2/login", postData, Encoding.UTF8, "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.80 Safari/537.36", ck, out outCookies);
            if (rt.status == 0)
            {
                ck = new CookieContainer();

                if (outCookies != null)
                {
                    foreach (Cookie item in outCookies)
                    {
                        ck.Add(item);
                    }
                }
            }
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            try
            {
                PostData();
            }
            catch (Exception ex)
            {
                WirteLog(ex.Message + ex.StackTrace);
            }
          
        }

        /// <summary>
        /// 重写错误
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Window_Error(object sender, HtmlElementErrorEventArgs e)
        {
            //忽略该错误并抑制错误对话框 
            e.Handled = true;
        }

        /// <summary>
        /// 将Unix时间戳转换为DateTime类型时间
        /// </summary>
        /// <param name="d">double 型数字</param>
        /// <returns>DateTime</returns>
        public System.DateTime ConvertIntDateTime(double d)
        {
            System.DateTime time = System.DateTime.MinValue;
            System.DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1));
            time = startTime.AddMilliseconds(d);
            return time;
        }

        /// <summary>
        /// 将c# DateTime时间格式转换为Unix时间戳格式,返回格式：1468482273277
        /// </summary>
        /// <param name="time">时间</param>
        /// <returns>long</returns>
        public long ConvertDateTimeInt(System.DateTime time)
        {
            //double intResult = 0;
            System.DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1, 0, 0, 0, 0));
            //intResult = (time- startTime).TotalMilliseconds;
            long t = (time.Ticks - startTime.Ticks) / 10000;            //除10000调整为13位
            return t;
        }

        private string jsonString(string s)
        {
            char[] temp = s.ToCharArray();
            int n = temp.Length;
            for (int i = 0; i < n; i++)
            {
                if (temp[i] == ':' && temp[i + 1] == '"')
                {
                    for (int j = i + 2; j < n; j++)
                    {
                        if (temp[j] == '"')
                        {
                            if (temp[j + 1] != ',' && temp[j + 1] != '}')
                            {
                                temp[j] = '”';
                            }
                            else if (temp[j + 1] == ',' || temp[j + 1] == '}')
                            {
                                break;
                            }
                        }
                    }
                }
                else if (temp[i] == '<' && (temp[i + 1] == '!'|| (temp[i + 2] == '!')))
                {
                    for (int j = i + 2; j < n; j++)
                    {
                        if (temp[j] == '>')
                        {
                            break;
                        }
                        if (temp[j] == '"')
                        {
                            temp[j] = '”';
                        }
                        if (temp[j] == '\\')
                        {
                            temp[j] = ' ';
                        }
                    }
                }
            }
            return new String(temp);
        }

        /// <summary>
        /// 记录请求数据
        /// </summary>
        /// <param name="groupId"></param>
        /// <param name="param"></param>
        private void AddJobRecord(int groupId, ReqMessagePage param)
        {
            JobRecord jobObj = new JobRecord
            {
                CreatedDate = DateTime.Now,
                JobId = (int)JobEnum.WxMsgCollect,
                DataCategoryID = groupId,
                FailCount = 0,
                SuccessCount = 0,
                Param = param.ToJSON()
            };
            jobService.Insert(jobObj);
        }

        private void ErrorCollect()
        {
            try
            {
                JobRecord info = jobService.GetLastExcuteJobRecordInfo(JobEnum.WxMsgCollect);
                if (info != null && info.LastDataRecordTime == DateTime.MinValue && info.SuccessCount == 0)
                {
                    ReqMessagePage obj = JsonConvert.DeserializeObject<ReqMessagePage>(info.Param);
                    List<GcGroupUser> userList = groupUserService.GetListByGroupId(info.DataCategoryID);
                    GetUserChatListUp(obj.WxId, info.DataCategoryID, obj.MsgId, obj.MsgIndex, userList, true);
                }
            }
            catch (Exception ex)
            {

                WirteLog(ex.Message + ex.StackTrace);
            }
            
        }

        private void WirteLog(string msg)
        {
            try
            {
                string filePath = string.Format("{0}/err.txt", Application.StartupPath);
                LogWriteLock.EnterWriteLock();
                if (!File.Exists(filePath))
                {
                    File.Create(filePath).Close();
                }
                using (StreamWriter sw = new StreamWriter(filePath, true))
                {
                    sw.WriteLine(msg);
                    sw.Dispose();
                }
            }
            catch (FileNotFoundException fileCe)
            {
                throw fileCe;
            }
            catch (Exception ce)
            {
                throw ce;
            }
            finally
            {
                //退出写入模式，释放资源占用

                LogWriteLock.ExitWriteLock();
            }

        }
    }
}
